﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using log4net;
using Sharp.DataTransferObject;
using Sharp.Infrastructure.Interfaces;
using Sharp.Infrastructure.WebApiClient;
using Sharp.ServiceContracts;

namespace Sharp.Portal
{
    /// <summary>
    /// 平台
    /// </summary>
    public class Platform
    {
        private static readonly object LockHelper = new object();
        /// <summary>
        /// 常见非平台dll的名单
        /// </summary>
        public static string[] ThirdpartyDlls = { "Antlr3.Runtime.dll", "AutoMapper.dll", "CommonServiceLocator.dll", "Microsoft.", "Newtonsoft.", "System.", "WebGrease.dll", "netfx.force.conflicts.dll", "Unity.", "log4net", "Owin", "Ext.Net", "log4net.dll", "EntityFramework", "MySql.Data", "WebMatrix", "ZKWeb", "RazorGenerator", "netstandard", "Castle", "Transformer.NET", "WebActivatorEx" };

        /// <summary>
        /// 初始化平台
        /// </summary>
        public static void InitPortal(params Assembly[] startupAssembles)
        {

            var filepath = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", "");
            var filepaths = new DirectoryInfo(Path.GetDirectoryName(filepath)).GetFiles("*.dll").Where(file => !ThirdpartyDlls.Any(i => file.Name.StartsWith(i, StringComparison.CurrentCultureIgnoreCase))).ToList();

            var bootstrapPlugins = new List<IBootstrapPlugin>();
            List<Assembly> assemblies = new List<Assembly>();
            if (startupAssembles != null)
            {
                assemblies.AddRange(startupAssembles);
            }

            filepaths.ForEach(file =>
            {
                byte[] fileData = File.ReadAllBytes(file.FullName);
                var assembly = Assembly.Load(fileData);

                if (assemblies.All(m => m.FullName != assembly.FullName))
                {
                    assemblies.Add(assembly);
                }
            });

            assemblies.ForEach(assembly =>
            {
                Type[] types;
                try
                {
                    types = assembly.GetTypes();
                }
                catch
                {
                    ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
                    log.Error(assembly.FullName + "加载错误，已经跳过。");
                    return;
                }

                foreach (var t in types)
                {
                    if (t.GetInterface(nameof(IBootstrapPlugin)) == null) continue;

                    var instance = (IBootstrapPlugin)assembly.CreateInstance(t.FullName ?? throw new InvalidOperationException());
                    if (instance != null)
                    {
                        instance.StartupAssembles = assemblies.ToArray();
                        bootstrapPlugins.Add(instance);
                    }
                }
            });

            bootstrapPlugins = bootstrapPlugins.OrderByDescending(x => x.Order).ToList();


            //先执行同步
            bootstrapPlugins.ForEach(x =>
            {
                try
                {
                    x.Initialize();
                }
                catch (Exception ex)
                {
                    ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
                    log.Error(ex);
                    throw;
                }
            });
            try
            {
                var tasks = bootstrapPlugins.Select(x => x.InitializeAsync()).ToArray();
                Task.WaitAll(tasks, 10000);
            }
            catch (Exception ex)
            {
                ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
                log.Error(ex);
                throw;
            }
        }

        #region 全局权限

        private static List<PermissionDTO> _permissions;

        /// <summary>
        /// 全局权限
        /// </summary>
        /// <returns></returns>
        public static IList<PermissionDTO> AllPermission()
        {
            if (_permissions == null)
            {
                lock (LockHelper)
                {
                    if (_permissions == null)
                    {
                        using (var proxy = new WebApiClientServiceProxy<IUserService>())
                        {
                            _permissions = proxy.Channel.AllPermissions().Result.ToList();
                        }
                    }
                    return _permissions;

                }
            }
            return _permissions;
        }

        #endregion

        #region 获取主数据

        private static readonly ConcurrentDictionary<string, IEnumerable<MasterDataSimpleDTO>> MasterData =
            new ConcurrentDictionary<string, IEnumerable<MasterDataSimpleDTO>>();

        /// <summary>
        /// 获取主数据
        /// </summary>
        /// <param name="category"></param>
        /// <returns></returns>
        public static IEnumerable<MasterDataSimpleDTO> GetMasterData(string category)
        {
            return MasterData.GetOrAdd(category, key =>
            {
                IList<MasterDataSimpleDTO> data;
                using (var proxy = new WebApiClientServiceProxy<IPlatformService>())
                {
                    data = proxy.Channel.GetMasterDataByCategory(category);
                }
                MasterData.TryAdd(category, data);
                return data;
            });
        }

        #endregion


    }
}